﻿using System;
using System.Configuration;
using System.Web;
using System.Security.Cryptography;
using System.Text;
using System.IO;

namespace RazakiBLL
{
    public static class Encryption
    {
        /// <summary>
        /// 16 bytes
        /// </summary>
        private const string _INITIALIZATION_VECTOR = "A0B1C2D3E4F5G6H7";

        private static readonly string _encryptLock = string.Empty;

        private static readonly string _decryptLock = string.Empty;

        private static string StaticKey
        {
            get { return ConfigurationManager.AppSettings["CipherKey"]; }
        }

        /// <summary>
        /// symmetric algorithm
        /// </summary>
        /// <param name="plain"></param>
        /// <param name="key">32 characters (32 bytes)</param>
        /// <returns></returns>
        public static string Encrypt(string plain, string key, bool isKeyStatic = false)
        {
            lock (_encryptLock)
            {
                string result;
                byte[] bytesOfKey;

                using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
                {
                    if (isKeyStatic)
                        bytesOfKey = Encoding.UTF8.GetBytes(StaticKey);
                    else
                        bytesOfKey = Encoding.UTF8.GetBytes(key);

                    var bytesOfIV = Encoding.UTF8.GetBytes(_INITIALIZATION_VECTOR);
                    var bytesOfOriginal = Encoding.UTF8.GetBytes(plain);
                    ICryptoTransform decryptor = rijndaelManaged.CreateEncryptor(bytesOfKey, bytesOfIV);

                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        using (
                            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write)
                            )
                        {
                            using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
                            {
                                streamWriter.Write(plain);
                            }

                            result = Convert.ToBase64String(memoryStream.ToArray());
                            result = result.Replace("+", "_");
                        }
                    }
                }

                return result;
            }
        }

        public static string Decrypt(string cipher, string key, bool isKeyStatic = false)
        {
            lock (_decryptLock)
            {
                string result;
                byte[] bytesOfKey;

                cipher = cipher.Replace("_", "+");

                using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
                {
                    if (isKeyStatic)
                        bytesOfKey = Encoding.UTF8.GetBytes(StaticKey);
                    else
                        bytesOfKey = Encoding.UTF8.GetBytes(key);

                    var bytesOfIV = Encoding.UTF8.GetBytes(_INITIALIZATION_VECTOR);
                    Byte[] bytesOfEncrypted = Convert.FromBase64String(cipher);
                    ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor(bytesOfKey, bytesOfIV);

                    using (MemoryStream memoryStream = new MemoryStream(bytesOfEncrypted))
                    {
                        using (
                            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)
                            )
                        {
                            using (StreamReader streamReader = new StreamReader(cryptoStream))
                            {
                                result = streamReader.ReadToEnd();
                            }
                        }
                    }
                }

                return result;
            }
        }
    }
}